package socks

import (
	"encoding/binary"
	"errors"

	"gitee.com/cjianwen/go/iohelper"
)

var (
	errBuffLenIsNotEnoughRead  = errors.New("buff length is not enough to read")
	errBuffLenIsNotEnoughWrite = errors.New("buff length is not enough to write")
)

const (
	cDefHeadSign = uint32(0xABCDEF99) // 默认头部标识
)

type DefMsgHead struct {
	signature uint32
	bodyLen   uint32
	Cmd       uint32
}

type DefPackData struct {
	Head DefMsgHead
	Data []byte
}

type defPackHelper struct {
	signValues []byte
}

func (p *defPackHelper) ReadPack(rd *iohelper.ReadHelper, d *DefPackData) (err error) {
	// _, err = rd.ReadMsgSignature(int64(cDefHeadSign), 4)
	// if err != nil {
	// 	return err
	// }
	// 这里优化一下，不用每次转换
	_, err = rd.ReadMsgSignatureBytes(p.signValues)
	if err != nil {
		return err
	}
	// d.Head.signature = cDefHeadSign   这个可以不要
	// 开始读消息头，上面已经读过分隔符了，这里不用再读了
	if d.Head.bodyLen, err = rd.ReadUint32(); err == nil {
		if d.Head.Cmd, err = rd.ReadUint32(); err == nil {
			//再读消息体
			if d.Head.bodyLen > 0 {
				d.Data = make([]byte, d.Head.bodyLen)
				var n int // 让下面的错误能返回
				n, err = rd.Read(d.Data)
				if err == nil && (n != int(d.Head.bodyLen)) {
					err = errBuffLenIsNotEnoughRead
				}
			}
		}
	}
	return err
}

func (p *defPackHelper) WritePack(w *iohelper.WriteHelper, d *DefPackData) (err error) {
	_, err = w.WriteUint32(cDefHeadSign)
	if err == nil {
		d.Head.bodyLen = uint32(len(d.Data))
		if _, err = w.WriteUint32(d.Head.bodyLen); err == nil {
			if _, err = w.WriteUint32(d.Head.Cmd); err == nil {
				if d.Head.bodyLen > 0 { // 写数据体
					var n int
					if n, err = w.Write(d.Data); (n != int(d.Head.bodyLen)) && err == nil {
						err = errBuffLenIsNotEnoughWrite
					}
				}
			}
		}
	}
	return err
}

func NewDefPackHelper(byteOrd binary.ByteOrder) *defPackHelper {
	vs := make([]byte, 4)
	byteOrd.PutUint32(vs, cDefHeadSign)
	return &defPackHelper{signValues: vs}
}

// 发数据时用
func NewDefPackWithData(cmd uint32, data []byte) *DefPackData {
	return &DefPackData{Head: DefMsgHead{signature: cDefHeadSign, Cmd: cmd, bodyLen: uint32(len(data))}, Data: data} // 头部标识非常重要
}
